package com.authsphere.security.account.redis.lock;

import com.authsphere.common.utils.JsonUtils;
import com.authsphere.security.account.api.lock.LockedAccount;
import com.authsphere.security.account.api.lock.LockoutRepository;
import com.authsphere.security.account.common.config.SecurityAccountConfig;
import com.google.common.collect.Lists;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.CollectionUtils;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * @program: AuthSphere
 * @description:
 * @author: YuKai Fan
 * @create: 2025/3/14 10:11
 **/
public class RedisLockoutRepository implements LockoutRepository {

    private String lockPrefix;
    private long expireSeconds = 3600;
    private final StringRedisTemplate redisTemplate;
    private final SecurityAccountConfig.LockAccountConfig lockAccountConfig;

    public RedisLockoutRepository(SecurityAccountConfig.LockAccountConfig lockAccountConfig, StringRedisTemplate redisTemplate) {
        this.lockAccountConfig = lockAccountConfig;
        this.redisTemplate = redisTemplate;
        setLockPrefix(lockAccountConfig.getLockPrefix());
        setExpireSeconds(lockAccountConfig.getLockIntervalTime());
    }

    @Override
    public void save(LockedAccount lockedAccount) {
        String username = lockedAccount.getUsername();
        String key = buildKey(username);
        redisTemplate.opsForValue()
                .set(key, Objects.requireNonNull(JsonUtils.toJsonString(lockedAccount)), expireSeconds, TimeUnit.SECONDS);
    }

    @Override
    public void update(LockedAccount lockedAccount) {
        String username = lockedAccount.getUsername();
        String key = buildKey(username);
        redisTemplate.opsForValue()
                .set(key, Objects.requireNonNull(JsonUtils.toJsonString(lockedAccount)), expireSeconds, TimeUnit.SECONDS);
    }

    @Override
    public LockedAccount findByUsername(String username) {
        String value = redisTemplate.opsForValue()
                .get(buildKey(username));
        return JsonUtils.parse(value, LockedAccount.class);
    }

    @Override
    public void deleteByUsername(String username) {
        redisTemplate.delete(buildKey(username));
    }

    @Override
    public List<LockedAccount> getLockedAccounts(String username) {
        String key = buildKey(username);
        Set<String> keys = redisTemplate.keys(key);
        if (CollectionUtils.isEmpty(keys)) {
            return Collections.emptyList();
        }
        List<String> valueList = redisTemplate.opsForValue()
                .multiGet(keys);
        if (CollectionUtils.isEmpty(valueList)) {
            return Collections.emptyList();
        }
        return valueList.stream().map(value -> JsonUtils.parse(value, LockedAccount.class)).toList();
    }

    @Override
    public List<String> findAllLockedAccounts() {
        Set<String> keys = redisTemplate.keys(buildKey("*"));
        assert keys != null;
        return Lists.newArrayList(keys);
    }

    private String buildKey(String username) {
        return lockPrefix + username;
    }

    public void setExpireSeconds(long expireSeconds) {
        this.expireSeconds = expireSeconds;
    }

    public void setLockPrefix(String lockPrefix) {
        this.lockPrefix = lockPrefix;
    }
}
